/*
 * p2sp.h
 *
 *  Created on: 2009-10-31
 *      Author: root
 */

#ifndef P2SP_H_
#define P2SP_H_

#include "packet.h"
#include "app.h"
#include "timer-handler.h"
#include "ns-process.h"
#include "udp-p2sp.h"

#define BROADCAST_ID 0xffffffff
#define CURRENT_TIME Scheduler::instance().clock()
#define MAXGROUPSIZE 128

/*//p2sp packet types
typedef enum p2sp_type {
  PEER_REQUEST = 1,
  PEER_DATA = 2,
  SRVR_REQUEST = 3,
  SRVR_DATA = 4,
  IS_RECVING = 5
} p2sp_t;*/

//p2sp packet types
typedef enum p2sp_state {
  IDLE = 1,
  BUSY = 2,
} p2sp_state_t;

typedef enum peer_tx {
  RANDOM = 1,
  PENDING = 2,
}peer_tx_t;



class p2spSrvrApp;
class p2spClientApp;


//Timer Definition
//Do I need any timer ?
/*class ReqTimer : public TimerHandler {
  public:
      ReqTimer(p2spClientApp* t) : TimerHandler(), t_(t) {deadline = 0; remain_time = -1;}
      inline virtual void expire(Event*);
      void freeze();
      void resume();
      void set(double);
      void reset(double);
  protected:
      p2spClientApp* t_;
      double remain_time;
      double deadline;
};*/

class MsRateTimer : public TimerHandler {
  public:
	MsRateTimer(p2spClientApp* t) : TimerHandler(), t_(t) {}
      inline virtual void expire(Event*);
      void set(double);
      void reset(double);
  protected:
      p2spClientApp* t_;

};

class SrvrReqTimer : public TimerHandler {
  public:
      SrvrReqTimer(p2spClientApp* t) : TimerHandler(), t_(t) {}
      inline virtual void expire(Event*);
      void set(double);
      void reset(double);
  protected:
      p2spClientApp* t_;

};

class PeerBcastTimer : public TimerHandler {
  public:
	PeerBcastTimer(p2spClientApp* t) : TimerHandler(), t_(t) {}
      inline virtual void expire(Event*);
/*      void freeze();
      void resume();*/
      void set(double);
      void reset(double);
      double set_time_;
      void postpone(double);
  protected:
      p2spClientApp* t_;
/*      double remain_time;
      double deadline;*/

};

class PeerJoinTimer : public TimerHandler {
  public:
	PeerJoinTimer(p2spClientApp* t) : TimerHandler(), t_(t) {}
      inline virtual void expire(Event*);
/*      void freeze();
      void resume();*/
      void set(double);
      void reset(double);
      double set_time_;
      void postpone(double);
  protected:
      p2spClientApp* t_;
/*      double remain_time;
      double deadline;*/
};



//AppData struct for p2sp App
/*class p2spAppData : public AppData {
public:
        p2sp_t type_;         //packet type?
        uint16_t chunk_id_;    //chunk id
        uint32_t req_bmp_[MAXBMPS];  //request bitmap put into appdata
        int nbytes_;   //bytes for p2sp pkt
        nsaddr_t src_id_;
        nsaddr_t dst_id_;
        int seqno_;

public:
        p2spAppData() : AppData(P2SP_DATA) {}

        inline p2sp_t& type() { return type_; }
        virtual int size() const { return sizeof(p2spAppData); }
        virtual AppData* copy() { return (new p2spAppData(*this)); }
};*/



//P2SP Client Application Class Definition
class p2spClientApp : public Application {
  public:
        p2spClientApp();
        void send_srvr_req();
        void send_peer_join();
        void send_peer_data(); //send p2sp packet, may include data request, broadcast data
        double data_tx_wnd();
        int select_tx_chunk();
        virtual void process_data(int size, AppData* data);
        inline int p2sp_enable() {return p2sp_enable_;}
        void update_rate();

        double wwan_rate_;
        double wlan_rate_;
        int infomap_size_;

        int all_same_[MAXGROUPSIZE];
        int same_conf_;
/*        double peer_req_jitter_;
        double peer_data_jitter_;
        double peer_data_timeout_;*/
        double srvr_data_timeout_;

        double guard_time_;
        double chk_trans_time_;
        double co_time_;
        int peer_id_;
        int is_member_;
        int join_ready_;

        int chunksize_;
        int chkmap_size_;
        uint16_t next_chunk_;
        double rate_interval_;
        char logRate_[1024];
        int interrput_;


  protected:
        int command(int argc, const char*const* argv);
        void start();   //start sending or requesting data;
        void stop();    //stop requesting data?
//        void assemble(uint16_t chunkid);        //assemble downloaded chunks
//        void rx_done();
//        void dropchunk();
        bool bhasChunk(uint16_t chunkid);
        bool whasChunk(uint16_t chunkid);
//        void resetPendingBit(uint16_t chunkid);
//        void updatePendingBmp(unsigned char *rq_bmp);
        void update_chkmap(unsigned char *chkmap, nsaddr_t src_id);
        int set_chkmap(unsigned char *chkmap, uint16_t chunkid);
        int select_req_id();
        void rx_from_srvr(uint16_t chunkid);
        void rx_from_peer(uint16_t chunkid);
        void reset_pri(uint16_t chunkid);
        int get_infomap(unsigned char *ourchkmap);
        void gen_chkmap(int index, unsigned char *inchkmap, unsigned char *ourchkmap);


  private:
        void init();
        virtual void recv_msg(int nbytes, const char *msg = 0);

//        ReqTimer req_timer_;
        MsRateTimer rate_timer_;
        SrvrReqTimer srvr_req_timer_;
        PeerBcastTimer peer_bcast_timer_;
        PeerJoinTimer peer_join_timer_;
        int filesize_;
        int running_;
        int nChunks_;


        unsigned char w_chkmap_[MAX_CHKMAP];
        unsigned char l_chkmap_[MAX_CHKMAP];
        unsigned char b_chkmap_[MAX_CHKMAP];
        unsigned char c_chkmap_[MAX_CHKMAP];
        //unsigned char chkmap_info[4];

        uint16_t primap_[MAX_CHKMAP*8];
        nsaddr_t srvr_id_;

        bool rx_done_;
        p2sp_state_t state_;
        peer_tx_t peer_tx_type_;

        int peer_down_;
        int srvr_down_;
        int peer_up_;
        int peer_info_up_;
//        double max_tx_wnd_;
        int group_size_;
        int com_size_;
        int seqno_;

        int p2sp_enable_;
/*        double fetch_time_;
        */
        double start_time_;

        double ms_rate_;
        int add_bytes_;

};

//P2SP Server Application Class Definition
class p2spSrvrApp : public Application {
  public:
        p2spSrvrApp();
        void send_p2sp_pkt(nsaddr_t,  int);
        virtual void process_data(int size, AppData* data);

  protected:
        int command(int argc, const char*const* argv);
        void start();   //start p2sp Service, wait for data request
        void stop();    //stop p2sp Service
  private:
//        void init();
        virtual void recv_msg(int nbytes, const char *msg = 0);

//        int select_chunk(unsigned char*);
        int running_;
        int chunksize_;
        int filesize_;
        int seqno_;
        int dbgno_;
        int chkmap_size_;

//        uint16_t tx_Pending_[MAXBMPS*8];





};

#endif /* P2SP_H_ */
